//========================================================================
//Copyright 2007-2010 David Yu dyuproject@gmail.com
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at 
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================

/*
 * Copyright (c) 2009 Jens Scheffler (appenginefan.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See
 * the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.dyuproject.kvstore;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.base.Function;

/**
 * Represents a simple way of persisting a particular object type.
 * 
 */
public interface Store<T>
{

    /**
     * Get the serializer
     * 
     * @return Serializer
     */
    public Serializer<T> getSerializer();
    
    /* STORE WRITE OPERATIONS */

    /**
     * Puts an entry in the store.
     * 
     * @param key
     *            the key to modify
     * @param value
     *            the value to add or replace(if existing)
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while storing data
     */
    public void put(String key, T value);

    /**
     * Deletes an entry from the store.
     * 
     * @param key
     *            the key to look up the data from
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public void delete(String key);
    
    /**
     * Deletes an entry from the store.
     * 
     * @param key
     *            the key to look up the data from
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public void delete(List<String> keys);

    /**
     * Modifies an entry in the store.
     * 
     * @param key
     *            the key to modify
     * @param mutator
     *            a function that applies a change to the data and stores the
     *            new result. If the data does not exist in the store yet, null
     *            will be passed in. If the data should be deleted from the
     *            store, the function will return null.
     * @return the data that was stored
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while storing data
     */
    public T mutate(String key, Function<? super T, ? extends T> mutator);
    
    /**
     * Modifies an entry in the store.
     * 
     * @param key
     *            the key to modify
     * @param mutator
     *            a function that applies a change to the data and stores the
     *            new result. If the data does not exist in the store yet, null
     *            will be passed in. If the data should be deleted from the
     *            store, the function will return null.
     * @param maxRetries
     *            the maximum retries for the mutation.
     * @return the data that was stored
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while storing data
     */
    public T mutate(String key, Function<? super T, ? extends T> mutator, int maxRetries);

    /**
     * Modifies an entry in the store.
     * 
     * @param mutableKey
     *            the mutable key to modify.  If the key is modified on the 
     *            mutation iteration, the current transaction will be discarded 
     *            and a new transaction will be made for the mutation based on 
     *            the new key.
     * @param mutator
     *            a function that applies a change to the data and stores the
     *            new result as raw data (byte array). If the data does not
     *            exist in the store yet, null will be passed in. If the data
     *            should be deleted from the store, the function will return
     *            null.
     * @return the data that was stored
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while storing data
     */
    public T mutateRaw(Mutable<String> mutableKey, Function<? super byte[], ? extends T> mutator);
    
    /**
     * Modifies an entry in the store.
     * 
     * @param mutableKey
     *            the mutable key to modify.  If the key is modified on the 
     *            mutation iteration, the current transaction will be discarded 
     *            and a new transaction will be made for the mutation based on 
     *            the new key.
     * @param mutator
     *            a function that applies a change to the data and stores the
     *            new result as raw data (byte array). If the data does not
     *            exist in the store yet, null will be passed in. If the data
     *            should be deleted from the store, the function will return
     *            null.
     * @param maxRetries
     *            the maximum retries for the mutation.
     * @return the data that was stored
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while storing data
     */
    public T mutateRaw(Mutable<String> mutableKey, Function<? super byte[], ? extends T> mutator, 
            int maxRetries);

    /* STORE READ OPERATIONS */
    
    /**
     * Gets an entry from the store.
     * 
     * @param key
     *            the key to look up the data from
     * @return the data or null, if the store does not contain data
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public T get(String key);
    
    /**
     * Gets a list of values from the store.
     * 
     * @param keys
     *            the multiple keys to look up the data from
     * @return the list values or empty, if the store does not contain data
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public List<T> get(List<String> keys);

    /**
     * Gets a list of entries from the store.
     * 
     * @param keys
     *            the multiple keys to look up the data from
     * @return the list values or empty, if the store does not contain data
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public List<Entry<String, T>> getEntries(List<String> keys);

    /**
     * Finds zero or more entries that are within a given range
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max key/value pairs, ordered by key
     */
    public List<Map.Entry<String, T>> scanEntries(String start, String end, int max);

    /**
     * Finds zero or more entries that are within a given range, but orders in
     * the opposite direction. Useful for pagination to jump to the end of a
     * range and get the "last ten" entries
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max key/value pairs, ordered by key in descending
     *         order
     */
    public List<Map.Entry<String, T>> scanEntriesReverse(String start, String end, int max);
    
    /**
     * Finds zero or more values that are within a given range
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max values, ordered by key
     */
    public List<T> scan(String start, String end, int max);
    
    /**
     * Finds zero or more entries that are within a given range, but orders in
     * the opposite direction. Useful for pagination to jump to the end of a
     * range and get the "last ten" entries
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max values, ordered by key in descending
     *         order
     */
    public List<T> scanReverse(String start, String end, int max);

    /**
     * Finds zero or more entries that are within a given range. Only returns
     * the keys.
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max keys, ordered by key
     */
    public List<String> keyScan(String start, String end, int max);

    /**
     * Finds zero or more entries that are within a given range, but orders in
     * the opposite direction. Only returns the keys.
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max keys, ordered by key in descending
     *         order
     */
    public List<String> keyScanReverse(String start, String end, int max);
    
    /* CUSTOM SERIALIZERS - useful for generating views for yoour entities */

    /**
     * Gets an entry from the store using a custom serializer.
     * 
     * @param key
     *            the key to look up the data from
     * @param serializer
     *            the custom serializer used for the result.
     * @return the data or null, if the store does not contain data
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public <V> V get(String key, Serializer<V> serializer);
    
    /**
     * Gets a list of values from the store using a custom serializer.
     * 
     * @param keys
     *            the multiple keys to look up the data from
     * @param serializer
     *            the custom serializer used for the result.
     * @return the list values or empty, if the store does not contain data
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public <V> List<V> get(List<String> keys, Serializer<V> serializer);

    /**
     * Gets a list of entries from the store using a custom serializer.
     * 
     * @param keys
     *            the multiple keys to look up the data from
     * @param serializer
     *            the custom serializer used for the result.
     * @return the list values or empty, if the store does not contain data
     * @exception NullPointerException
     *                if either of the arguments is null
     * @exception StoreException
     *                if something went wrong while loading data
     */
    public <V> List<Entry<String, V>> getEntries(List<String> keys, Serializer<V> serializer);

    /**
     * Finds zero or more entries that are within a given range.
     * Uses a custom serialzer.
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the custom serializer used for the result.
     * @return a list of up to max key/value pairs, ordered by key
     */
    public <V> List<Map.Entry<String, V>> scanEntries(String start, String end, int max, 
            Serializer<V> serializer);
    
    /**
     * Finds zero or more entries that are within a given range, but orders in
     * the opposite direction. Useful for pagination to jump to the end of a
     * range and get the "last ten" entries.
     * Uses a custom serialzer.
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the custom serializer used for the result.
     * @return a list of up to max key/value pairs, ordered by key in descending
     *         order
     */
    public <V> List<Map.Entry<String, V>> scanEntriesReverse(String start, String end, 
            int max, Serializer<V> serializer);
    
    /**
     * Finds zero or more values that are within a given range.
     * Uses a custom serialzer.
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the custom serializer used for the result.
     * @return a list of up to max values, ordered by key
     */
    public <V> List<V> scan(String start, String end, int max, Serializer<V> serializer);
    
    /**
     * Finds zero or more entries that are within a given range, but orders in
     * the opposite direction. Useful for pagination to jump to the end of a
     * range and get the "last ten" entries.
     * Uses a custom serialzer.
     * 
     * @param start
     *            a lower bound of the range of keys to look in (inclusive)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the custom serializer used for the result.
     * @return a list of up to max values, ordered by key in descending
     *         order
     */
    public <V> List<V> scanReverse(String start, String end, int max, 
            Serializer<V> serializer);

}
